/****
	Copyright 2011 Taras Kulbachka

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

		http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/
package com.atdevsoft.apps.abyss;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import android.content.ContentValues;
import android.util.Log;

public abstract class AbstractQuoteDownloader {
    public final static int STATUS_OK = 0;
    public final static int STATUS_SKIP_QUOTE = 1;
    public final static int STATUS_SKIP_PAGE = 2;
    public final static int STATUS_FALLBACK_PAGE = 3;
    public final static int STATUS_ABORT = 4;
    public final static int STATUS_NEED_SUBPROCESS = 5;    
	
    public interface OnPageProcessedListener {
        boolean onPageProcessed(final String pageName, final int quotesAdded, final int quotesSkipped); //if result is false we stop further processing (for future use if we decide to make cancel operation)
        void onAllPagesProcessed(final int resultCode, final int totalQuotesAdded, final int totalQuotesSkipped);
    }	    
	
	public int PageSavedQuotes;
	public int PageSkippedQuotes;
	public int TotalSavedQuotes;
	public int TotalSkippedQuotes;
	public String QuotesSitePageName;	
	public String NextSitePageRef;
	
	protected boolean mTerminateOnDuplicates;
	
	private String mTableName;
	private ContentValues data;	
    private OnPageProcessedListener mProcessedListener;
	


    public AbstractQuoteDownloader(String tableName) {
    	mTableName = tableName;
    }    
    
	protected abstract int getNearestSavedQuote(int quoteId);
	protected abstract int processTag(TagNode tag, ContentValues output, boolean fastDownload); // returns true if may iterate subnodes
	protected abstract String getPageAddress(String nextPageRef);
	
    private int iterateTags(Node node, ContentValues data, boolean fastDownload) throws ParserException {	    	
    	if (node instanceof TagNode) {
            TagNode tag = (TagNode)node;
            int status = processTag(tag, data, fastDownload);
            
            if (status == STATUS_SKIP_QUOTE) {            
            	PageSkippedQuotes++; 
            	return status;
            } else            
	            if ((status == STATUS_OK) && ((data.size() > 0))) {
	            	DatabaseHelper.databaseInsert(mTableName, null, data);
	            	PageSavedQuotes++;
	                data.clear();
	                return status;
	            } 
            if (status == STATUS_NEED_SUBPROCESS) {
            	status = STATUS_OK;
                data.clear();            	
            	NodeList nl = tag.getChildren();	            
            	if (nl != null)
            		for (NodeIterator i = nl.elements(); i.hasMoreNodes(); ) {
            			if ((status == STATUS_OK) || (status == STATUS_SKIP_QUOTE)) 
            				status = iterateTags(i.nextNode(), data, fastDownload);
            			else
            				return status;
	            }            	
            }
            return status;
    	}
    	return STATUS_OK;
    }		
        
    public int parsePage(String page, boolean terminateOnDuplicates, boolean fastDownload) {
    	mTerminateOnDuplicates = terminateOnDuplicates;
    	PageSavedQuotes = 0;
    	PageSkippedQuotes = 0;
    	if (data == null)	    		
    		data = new ContentValues();	
    	else
    		data.clear();
    	int status = STATUS_OK;
        DatabaseHelper.beginTransaction();
        try {
	       	try {
	       		Parser parser = null;
	       		String pageData = null;

	       		String url = page;
	    		String proxyHost = android.net.Proxy.getDefaultHost();
	    		int proxyPort = android.net.Proxy.getDefaultPort();

	    		HttpParams httpParameters = new BasicHttpParams();
	    		HttpConnectionParams.setConnectionTimeout(httpParameters, 5000);		
	    		HttpConnectionParams.setSoTimeout(httpParameters, 8000);
	    		HttpClient httpClient = new DefaultHttpClient(httpParameters);
	    		
	    		if (proxyPort > 0) {
	    			HttpHost proxy = new HttpHost(proxyHost, proxyPort);
	    			httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
	    		}
	    		HttpGet httpGet = new HttpGet(url);
	    		
	    		
	    		HttpResponse response;
				try {
					response = httpClient.execute(httpGet);
							
					if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
						BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "Cp1251"));
						StringBuilder sb = new StringBuilder();
						String line = null;
						while ((line = reader.readLine()) != null) {
							sb.append(line + System.getProperty("line.separator"));
						}
						
						pageData = sb.toString();
					}
				} catch (ClientProtocolException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
	       		
	       		if (pageData != null) {
					Lexer l = new Lexer(pageData);
					parser = new Parser(l);
				}

	       		if (parser != null) {
	       			for (NodeIterator i = parser.elements (); i.hasMoreNodes(); )
	       				if (status == STATUS_OK || status == STATUS_SKIP_QUOTE) 
	       					status = iterateTags(i.nextNode(), data, fastDownload);
	       				else
	       					return status;
	       		}
			} catch (ParserException e) {
				e.printStackTrace();
			}		
	       	DatabaseHelper.setTransactionSuccessful();					
        } finally {
        	DatabaseHelper.endTransaction();
        }
        return status;
    }
    
    public void parsePages(int pagesCount, boolean terminateOnDuplicates, boolean fastDownload, boolean reversePageNumbers) {
    	QuotesSitePageName = "";	
    	NextSitePageRef = null;
    	TotalSavedQuotes = 0;	
    	TotalSkippedQuotes = 0;
    	int status = STATUS_OK;
    	for (int i = 0; i < pagesCount; i ++) {
    		if (status != STATUS_ABORT) {
   				status = parsePage(getPageAddress(NextSitePageRef), terminateOnDuplicates, fastDownload);
				Log.d("abyss", "after page parsed");	    		
                if (mProcessedListener != null) {            		
                	if (!mProcessedListener.onPageProcessed(QuotesSitePageName, PageSavedQuotes, PageSkippedQuotes))
                		return;
                }	    		
    		}
    		TotalSavedQuotes += PageSavedQuotes;
    		TotalSkippedQuotes += PageSkippedQuotes;
    	}
        if (mProcessedListener != null) {            		
        	mProcessedListener.onAllPagesProcessed(status, TotalSavedQuotes, TotalSkippedQuotes);
        }	    	
    	
    }
    
    public void setOnPageProcessedListener(OnPageProcessedListener listener) {
    	mProcessedListener = listener;
    }

}
